package com.cjq.controller;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cjq.domain.Questionnaire;
import com.cjq.domain.User;
import com.cjq.service.QuestionnaireService;
import com.cjq.utils.Constant;
import com.cjq.utils.JwtUtils;
import com.cjq.utils.Result;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import javax.jms.Queue;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.Principal;
import java.time.Duration;
import java.util.*;

/**
 * @author junqiancai@foxmail.com
 * @since 2021/6/12 2:26
 */
@RestController
@Slf4j
public class QuestionnaireController {
    @Autowired
    private QuestionnaireService service;

    @Autowired
    private StringRedisTemplate redisTemplate;
    //注入存放消息的队列，用于下列方法一
    @Autowired
    private Queue queue;

    //注入springboot封装的工具类
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    //生产者接口，解决并发问题
    @PreAuthorize("hasRole('USER')")
    @PostMapping("/quest/mq")
    public Result postQuestInMq(@RequestBody Questionnaire questionnaire, Principal principal){
        Authentication auth = (Authentication) principal;
        @SuppressWarnings("unchecked")
        HashMap<String,Object> details = (HashMap<String, Object>) auth.getDetails();
        Integer userId = (Integer) details.get("userId");
        questionnaire.setUserId(userId);
        //生成消息放入队列中
        jmsMessagingTemplate.convertAndSend(queue, questionnaire);
        return Result.succeed(Result.CREATE,"成功提交打卡请求");
    }

    //轮询接口，查看打卡情况
    @PreAuthorize("hasRole('USER')")
    @GetMapping("/quest/polling")
    public Result pollingQuestInMq(Principal principal){
        Authentication auth = (Authentication) principal;
        @SuppressWarnings("unchecked")
        HashMap<String,Object> details = (HashMap<String, Object>) auth.getDetails();
        Integer userId = (Integer) details.get("userId");
        //获取打卡结果
        final String redisKey = Constant.POLLING_PREFIXED + userId;
        final String questResult = redisTemplate.opsForValue().get(redisKey);
        if(questResult==null)return Result.succeed(Result.NO_CONTENT,"轮询，无打卡结果");//mq中的消息未被处理
        redisTemplate.delete(redisKey);
        switch (questResult){
            case Constant.POLLING_SUCCESS:return Result.succeed(Result.SUCCESS,"轮询，打卡成功");
            case Constant.POLLING_FAIL:return Result.succeed(Result.Server_Error,"轮询，打卡失败");
            case Constant.POLLING_UNWANTED:return Result.succeed(Result.Params_Error,"轮询，今日不可重复打卡");
        }
        return Result.succeed(Result.Server_Error,"轮询，服务器出错");//mq中的消息未被处理
    }


    private boolean checkRedisNRS(Integer userId){
        //构造key
        final Calendar today = Calendar.getInstance();
        today.set(Calendar.HOUR_OF_DAY,0);
        today.set(Calendar.MINUTE,0);
        today.set(Calendar.SECOND,0);
        today.set(Calendar.MILLISECOND,0);
        String key = Constant.NON_REPEATED_SUBMIT+today.getTimeInMillis()+"-"+userId;
        if(Boolean.TRUE.equals(redisTemplate.hasKey(key)))
            return Boolean.TRUE.equals(redisTemplate.delete(key));
        return false;
    }
    @PreAuthorize("hasRole('USER')")
    @PostMapping("/quest")
    public Result postQuest(@RequestBody Questionnaire questionnaire, Principal principal){
        Authentication auth = (Authentication) principal;
        @SuppressWarnings("unchecked")
        HashMap<String,Object> details = (HashMap<String, Object>) auth.getDetails();
        Integer userId = (Integer) details.get("userId");
        if(!checkRedisNRS(userId))return Result.fail(400,"今日已打过卡");  //防止重复提交
        questionnaire.setUserId(userId);
        questionnaire.setClockInDate(new Date());
        Object addressJson = questionnaire.getAddressJson();
        Object dangerZoneJson = questionnaire.getDangerZoneJson();
        ObjectMapper om = new ObjectMapper();
        try {
            String address = om.writeValueAsString(addressJson);
            String dangerZone = om.writeValueAsString(dangerZoneJson);
            questionnaire.setAddress(address);
            questionnaire.setDangerZone(dangerZone);
            //看一下昨天有没有打卡
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH,-1);
            LambdaQueryWrapper<Questionnaire> wrapper = new LambdaQueryWrapper<Questionnaire>()
                    .eq(Questionnaire::getUserId,userId)
                    .eq(Questionnaire::getClockInDate, new java.sql.Date(calendar.getTimeInMillis()));
            Questionnaire lastQuest = service.getOne(wrapper);
            if(lastQuest!=null){
                questionnaire.setDuration(lastQuest.getDuration()+1);
            }
            else questionnaire.setDuration(1);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return Result.succeed(Result.Params_Error,"json解析异常");
        }
        service.save(questionnaire);
        return Result.succeed(Result.CREATE,"打卡成功");
    }

    @PreAuthorize("hasRole('USER')")
    @GetMapping("/quest")
    public Result getQuest(Principal principal){
        Authentication auth = (Authentication) principal;
        @SuppressWarnings("unchecked")
        HashMap<String,Object> details = (HashMap<String, Object>) auth.getDetails();
        Integer userId = (Integer) details.get("userId");
        QueryWrapper<Questionnaire> questWrapper = new QueryWrapper<>();
        questWrapper.eq("user_id",userId)
                    .orderByDesc("clock_in_date")
                    .last("limit 1");
        Questionnaire que = service.getOne(questWrapper);
        if(que!=null){
            JacksonJsonParser parser = new JacksonJsonParser();
            List<Object> address = parser.parseList(que.getAddress());
            List<Object> dangerZone = parser.parseList(que.getDangerZone());
            que.setAddressJson(address);
            que.setDangerZoneJson(dangerZone);
            final Date clockInDate = que.getClockInDate();  //上次打卡日期
            final Calendar today = Calendar.getInstance();  //今天
            today.set(Calendar.HOUR_OF_DAY,0);
            today.set(Calendar.MINUTE,0);
            today.set(Calendar.SECOND,0);
            today.set(Calendar.MILLISECOND,0);
            if(!clockInDate.equals(today.getTime())){
                //表示今天还未曾打卡,在redis中放入key:NRS-timeInMillis-userId,有效期一天
                redisTemplate.opsForValue().set(Constant.NON_REPEATED_SUBMIT+today.getTimeInMillis()+"-"+que.getUserId(),
                        "",
                        Duration.ofDays(Constant.NRS_EXPIRE));
            }
            return Result.succeed(Result.SUCCESS,"成功获取上次打卡数据",que);
        }
        return Result.succeed(Result.NO_CONTENT,"没有打卡记录");
    }

    @PreAuthorize("hasAnyRole('ADMIN','SUPER')")
    @GetMapping("/download/quest/all")
    public void getAllQuest(@RequestParam(value = "date",required = false)
                                  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date,
                                HttpServletResponse response) throws IOException {
        if(date==null)date = new Date();
        java.sql.Date targetDate = new java.sql.Date(date.getTime());
        List<Questionnaire> questionnaires = service.selectAllQuest(targetDate);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("全部健康上报数据", "UTF-8").replaceAll("\\+", "%20");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), Questionnaire.class).sheet("全部健康上报数据").doWrite(questionnaires);
    }

    @PreAuthorize("hasAnyRole('ADMIN','SUPER')")
    @GetMapping("/download/quest/risk")
    public void getRiskQuest(@RequestParam(value = "date",required = false)@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date,
                             HttpServletResponse response) throws IOException {
        if(date==null)date = new Date();
        java.sql.Date targetDate = new java.sql.Date(date.getTime());
        List<Questionnaire> questionnaires = service.selectRiskQuest(targetDate);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("风险健康上报数据", "UTF-8").replaceAll("\\+", "%20");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), Questionnaire.class).sheet("风险健康上报数据").doWrite(questionnaires);
    }

    @PreAuthorize("hasAnyRole('ADMIN','SUPER')")
    @GetMapping("/download/quest/exception")
    public void getExceptionQuest(@RequestParam(value = "date",required = false)@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date,
                                  HttpServletResponse response) throws IOException {
        if(date==null)date = new Date();
        java.sql.Date targetDate = new java.sql.Date(date.getTime());
        List<Questionnaire> questionnaires = service.selectExceptionQuest(targetDate);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("异常健康上报数据", "UTF-8").replaceAll("\\+", "%20");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), Questionnaire.class).sheet("异常健康上报数据").doWrite(questionnaires);
    }
}
